# frozen_string_literal: true

require 'spec_helper'

RSpec.describe VulnerabilityFeedback::DestroyService, '#execute', feature_category: :vulnerability_management do
  let(:project) { create(:project, :public, :repository) }
  let(:user)    { create(:user) }
  let(:vulnerability_feedback) { create(:vulnerability_feedback, feedback_type, project: project) }
  let(:revert_vulnerability_state) { true }
  let(:service_object) { described_class.new(project, user, vulnerability_feedback, revert_vulnerability_state: revert_vulnerability_state) }

  before do
    project.add_developer(user)
    stub_licensed_features(security_dashboard: true)
  end

  subject(:destroy_feedback) { service_object.execute }

  context 'when feedback_type is dismissal' do
    let(:feedback_type) { :dismissal }

    context 'when the user is authorized' do
      context 'when the `revert_vulnerability_state` argument is set as true' do
        context 'when the finding is not associated with a vulnerability' do
          it 'destroys the feedback' do
            expect { destroy_feedback }.to change { vulnerability_feedback.destroyed? }.to(true)
          end
        end

        context 'when the finding is associated with a vulnerability' do
          let(:finding) { create(:vulnerabilities_finding, :dismissed, project: project) }
          let(:vulnerability_feedback) { finding.dismissal_feedback }

          it 'changes the state of the vulnerability to `detected`' do
            expect { destroy_feedback }.to change { finding.vulnerability.reload.state }.from('dismissed').to('detected')
          end
        end
      end

      context 'when the `revert_vulnerability_state` argument is set as false' do
        let(:revert_vulnerability_state) { false }

        context 'when the finding is not associated with a vulnerability' do
          it 'destroys the feedback' do
            expect { destroy_feedback }.to change { vulnerability_feedback.destroyed? }.to(true)
          end
        end

        context 'when the finding is associated with a vulnerability' do
          let(:finding) { create(:vulnerabilities_finding, :dismissed, project: project) }
          let(:vulnerability_feedback) { finding.dismissal_feedback }

          it 'does not change the state of the vulnerability to `detected`' do
            expect { destroy_feedback }.not_to change { finding.vulnerability.reload.state }
          end
        end
      end
    end

    context 'when user is not authorized' do
      before do
        project.add_guest(user)
      end

      it 'raise error if permission is denied' do
        expect { destroy_feedback }.to raise_error(Gitlab::Access::AccessDeniedError)
      end
    end
  end

  context 'when feedback_type is issue' do
    let(:feedback_type) { :issue }

    it 'raise error as this type of feedback can not be destroyed' do
      expect { destroy_feedback }.to raise_error(Gitlab::Access::AccessDeniedError)
    end
  end

  context 'when feedback_type is merge_request' do
    let(:feedback_type) { :merge_request }

    it 'raise error as this type of feedback can not be destroyed' do
      expect { destroy_feedback }.to raise_error(Gitlab::Access::AccessDeniedError)
    end
  end
end
